﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI;
using System.ComponentModel;
using System.Web.UI.WebControls;

[assembly: WebResource("AfterEdge.Web.Resources.Scripts.UpdatePanelExtender.js", "text/javascript")]
namespace AfterEdge.Web.UI
{
    [TargetControlType(typeof(UpdatePanel))]
    public class UpdatePanelExtender : ExtenderControl, IPostBackEventHandler
    {
        private static readonly Object EventCommand;
        private UpdatePanelExtenderClientEvents _clientEvents;

        static UpdatePanelExtender()
        {
            EventCommand = new Object();
        }

        public event CommandEventHandler Command
        {
            add { base.Events.AddHandler(EventCommand, value); }
            remove { base.Events.RemoveHandler(EventCommand, value); }
        }

        public String ValidationGroup
        {
            get { return (String)ViewState["ValidationGroup"]; }
            set { ViewState["ValidationGroup"] = value; }
        }

        public bool CausesValidation
        {
            get { return ViewState["CausesValidation"] != null ? (bool)ViewState["CausesValidation"] : false; }
            set { ViewState["CausesValidation"] = value; }
        }

        public String CommandArgument
        {
            get { return (String)ViewState["CommandArgument"]; }
            set { ViewState["CommandArgument"] = value; }
        }

        [Category("Behavior")]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public UpdatePanelExtenderClientEvents ClientEvents
        {
            get
            {
                if (this._clientEvents == null)
                    this._clientEvents = new UpdatePanelExtenderClientEvents();

                return this._clientEvents;
            }
        }

        protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
        {
            ScriptBehaviorDescriptor descriptor = new ScriptBehaviorDescriptor("AfterEdge.Web.UI.UpdatePanelExtender", targetControl.ClientID);
            descriptor.AddProperty("id", this.ClientID);
            if (!String.IsNullOrEmpty(this.ValidationGroup))
                descriptor.AddProperty("validationGroup", this.ValidationGroup);
            descriptor.AddProperty("causesValidation", this.CausesValidation);
            if (!String.IsNullOrEmpty(this.CommandArgument))
                descriptor.AddProperty("commandArgument", this.CommandArgument);

            foreach (String key in this.ClientEvents.Handlers.Keys)
            {
                String eventHandler = this.ClientEvents.Handlers[key];
                if (!String.IsNullOrEmpty(eventHandler))
                    descriptor.AddEvent(key, eventHandler);
            }

            return new ScriptDescriptor[] { descriptor };
        }

        protected override IEnumerable<ScriptReference> GetScriptReferences()
        {
            ScriptReference reference = new ScriptReference();
            reference.Assembly = this.GetType().Assembly.FullName;
            reference.Name = "AfterEdge.Web.UI.UpdatePanelExtender.ClientScripts.UpdatePanelExtender.js";

            return new ScriptReference[] { reference };
        }

        protected override void OnInit(EventArgs e)
        {
            // We need to register an Async PostBack trigger for the extender control so the
            // update panel can still do an async postback.  This is great because then we can 
            // handle the Command event of the UpdatePanelExtender and do whatever we need to do.
            UpdatePanel panel = this.NamingContainer.FindControl(this.TargetControlID) as UpdatePanel;
            if (panel != null)
            {
                AsyncPostBackTrigger trigger = new AsyncPostBackTrigger();
                trigger.ControlID = this.ID;
                trigger.EventName = "Command";

                panel.Triggers.Add(trigger);
            }

            base.OnInit(e);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            // We need to write out some HTML element to the browser so that the postback 
            // is recognized from AsyncPostback trigger.
            writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
            writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none");
            writer.RenderBeginTag(HtmlTextWriterTag.Span);
            writer.RenderEndTag();
            
            base.Render(writer);
        }

        #region IPostBackEventHandler Members

        void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
        {
            CommandEventArgs args = new CommandEventArgs(String.Empty, eventArgument);
            OnCommand(args);
        }

        protected void OnCommand(CommandEventArgs e)
        {
            CommandEventHandler handler = (CommandEventHandler)base.Events[EventCommand];
            if (handler != null)
                handler(this, e);
        }

        #endregion
    }
}
